/**
 * @file bsp.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include <stdio.h>
#include <time.h>
#include "hal_adapter.h"
#include "bsp_adc.h"
#include "bsp_uart.h"
#include "bsp_wdt.h"
#include "bsp_eflash.h"
#include "bsp_debug.h"
#include "bsp_comm.h"
#include "cmsis_os2.h"
#include "bsp_rtc.h"

#include "global.h"

void SystemClock_Config(void);
static void SystemPower_Config(void);
void Error_Handler(void);

extern HAL_StatusTypeDef HAL_InitTick_Tim6(uint32_t TickPriority);


/// @brief BSP功能初始化
/// @param  
void bsp_init(void)
{
    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();
    
    /* Configure the system clock */
    SystemClock_Config();
    
    /* Configure the System Power */
    SystemPower_Config();

    /* Configure the Systick */
    HAL_InitTick_Tim6(1);
    
    rtc_init();
    
    /* 调试串口初始化 */
    bsp_debug_init();

    /* 仪表串口初始化 */
    bsp_comm_init();

    /* init bsp watchdog timer */
    bsp_wdt_init();

    /* initial the adc for reading the hardware version */
    bsp_adc_init();
}


/**
 * @brief 休眠唤醒配置
 */
void bsp_init_after_wakeup(void)
{
    SystemClock_Config();
}

extern uint32_t ulGetMillisecondsSinceBoot( int32_t IncludePendedTicks, int32_t IncludeStoppedTicks );
/**
 * @brief 获取自启动后的总时长.包括STOP MODE时长
 * @return uint32_t 时长单位ms
 */
uint32_t bsp_get_ms_since_boot(void)
{
    return ulGetMillisecondsSinceBoot(1,1);
}

extern uint64_t ullGetNanosecondsSinceBoot( int32_t IncludePendedTicks, int32_t IncludeStoppedTicks );

/**
 * @brief  获取自启动后的总时长.包括STOP MODE时长
 * @return uint64_t 时长单位ns
 */
uint64_t bsp_get_ns_since_boot(void)
{
    return ullGetNanosecondsSinceBoot(1,1);
}

/**
 * @brief 获取自启动后的总时长.包括STOP MODE时长
 * @return uint32_t 启动运行总时长,单位s
 */
uint32_t bsp_get_seconds_since_boot(void)
{
    return bsp_get_ms_since_boot() / 1000;
}

/**
 * @brief 判断当前时刻与start_time时刻相距是否超过了timeout ms
 * @param  start_time       开始时间
 * @param  timeout          超时时间,单位ms
 * @return true             计时器超时
 * @return false            计时器未超时
 */
bool bsp_ms_is_timeout(uint32_t start_time, uint32_t timeout)
{
    return (((bsp_get_ms_since_boot() - start_time) > timeout) ? true : false);
}

/**
 * @brief 判断当前时刻与start_time时刻相距是否超过了timeout ns
 * @param  start_time       开始时间
 * @param  timeout          超时时间,单位ns
 * @return true             计时器超时
 * @return false            计时器未超时
 */
bool bsp_ns_is_timeout(uint64_t start_time, uint32_t timeout)
{
	return (((bsp_get_ns_since_boot() - start_time) > timeout)? true : false);
}

/**
 * @brief 判断当前时刻与start_time时刻相距是否超过了timeout s
 * @param  start_time       开始时间
 * @param  timeout          超时间隔
 * @return true             计时器超时
 * @return false            计时器未超时
 */
bool bsp_seconds_is_timeout(uint32_t start_time, uint32_t timeout)
{
	uint32_t start_time_ms = start_time * 1000;
	uint32_t timeout_ms    = timeout    * 1000;
	return (((bsp_get_ms_since_boot() - start_time_ms) > timeout_ms)? true : false);
}


/**
 * @brief 底层重启设备，应用调用tbox_system_reboot替代
 */
void bsp_reboot(void)
{
    __disable_irq();
    HAL_NVIC_SystemReset();
}

#include "comm/co_heartbeat.h"
/**
 * @brief 关闭设备，休眠逻辑处理
 */
void bsp_poweroff(void)
{
    co_pwr();
}


/**
 * @brief  读取MCU芯片ID, 本函数仅对以下MCU有效: STM32
 * @param  id: [O], id[0]为U_ID[31:0],id[1]为U_ID[63:32],id[2]为U_ID[95:64], 可以为NULL;
 * @param  str: [O], 字符串格式, 各字节依次为[95:88][87:80][79:72][71:64][63:56][55:48][47:40][39:32][31:24][23:16][15:8][7:0]位,可以为NULL.
 * @retval 0:成功, others:错误码
 */
int32_t hdl_mcu_unique_devid_get(uint32_t id[3], char *str)
{
	if (id == NULL && str == NULL)
		return -EINVAL;

	uint32_t uid[3], uid_address;

	uid_address = 0x1FFF7A10;
	uid[0] = *((volatile uint32_t *)(uid_address + 0x00));
	uid[1] = *((volatile uint32_t *)(uid_address + 0x04));
	uid[2] = *((volatile uint32_t *)(uid_address + 0x08));
	if (id != NULL) {
		id[0] = uid[0];
		id[1] = uid[1];
		id[2] = uid[2];
	}
	if (str != NULL) {
		sprintf(str, 	  "%08X", uid[2]);
		sprintf(str + 8,  "%08X", uid[1]);
		sprintf(str + 16, "%08X", uid[0]);
	}
	return 0;
}


/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
#ifdef STM32U575xx
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
     */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
    {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV1;
    RCC_OscInitStruct.PLL.PLLM = 1;
    RCC_OscInitStruct.PLL.PLLN = 40;
    RCC_OscInitStruct.PLL.PLLP = 2;
    RCC_OscInitStruct.PLL.PLLQ = 2;
    RCC_OscInitStruct.PLL.PLLR = 4;
    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_1;
    RCC_OscInitStruct.PLL.PLLFRACN = 0;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_PCLK3;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV8;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
    {
        Error_Handler();
    }
#elif defined(STM32H563xx)
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main int32_ternal regulator output voltage
     */
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

    while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY))
    {
    }

    /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV2;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    RCC_OscInitStruct.LSIState = RCC_LSI_ON;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_PCLK3;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
    {
        Error_Handler();
    }

    /** Configure the programming delay
     */
    __HAL_FLASH_SET_PROGRAM_DELAY(FLASH_PROGRAMMING_DELAY_0);
#endif
}

/**
 * @brief Power Configuration
 * @retval None
 */
static void SystemPower_Config(void)
{
#ifdef STM32U575xx
    __HAL_RCC_PWR_CLK_ENABLE();

    HAL_PWREx_EnableVddA();
    HAL_PWREx_EnableVddIO2();
    /*
    * Disable the int32_ternal Pull-Up in Dead Battery pins of UCPD peripheral
    */
    HAL_PWREx_DisableUCPDDeadBattery();
#elif defined(STM32U575xx)
    
#endif
}




#define SLEEP_MODE_2
/* 进入stop模式 */
void bsp_enter_lowpower(void)
{
#ifdef SLEEP_MODE_1
    /*1 睡眠模式 */
    //使能PWR时钟
    __HAL_RCC_PWR_CLK_ENABLE();
    //暂停滴答时钟，防止通过滴答时钟中断唤醒
    HAL_SuspendTick();
    //进入睡眠模式
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
    //唤醒后继续下方代码执行
#endif
#ifdef SLEEP_MODE_2
    /*2 停机2模式 */
    CLEAR_BIT(SysTick->CTRL, (SysTick_CTRL_ENABLE_Msk));
    HAL_DBGMCU_EnableDBGStopMode();/* 允许在STOP模式下的调试模式 */

    //使能PWR时钟
    __HAL_RCC_PWR_CLK_ENABLE();
    //进入停机模式
    //HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
    HAL_PWREx_EnterSTOP2Mode(PWR_SLEEPENTRY_WFI);

    //停机模式唤醒后，系统自动使用MSIS(最高24MHZ)/HSI16时钟,调用该函数重新配置时钟
    bsp_init_after_wakeup();
#endif
#ifdef SLEEP_MODE_3
    /*3 待机模式 */

    //使能PWR时钟
    __HAL_RCC_PWR_CLK_ENABLE();
    //配置唤醒脚
    HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
    //清除WUF唤醒标志
    __HAL_PWR_CLEAR_FLAG(PWR_WAKEUP_FLAG1);


    //进入待机模式
    HAL_PWR_EnterSTANDBYMode();

    //唤醒后程序将重新运行
#endif
}

